Calling NAG Fortran Library Routines from C Language Programs
Using the NAG C Header Files on
Unix Systems
© The Numerical Algorithms Group Ltd, Oxford UK. 2005
A header file containing the function prototypes can be included in the user's program to allow the C compiler to check argument passage. Such a header file has been created for the current NAG Fortran Library. This was done automatically from the Library source code. This document explains how to call Fortran routines from C using the NAG header file. Note that if __STDC__ is not defined, no argument checking will be carried out.
DOUBLE PRECISION D double d;
INTEGER I int i;
LOGICAL L int l;
CHARACTER*n S char s[n];
DOUBLE COMPLEX Z struct {double re,im;} z;
All arguments are passed as pointers to a variable; this means that a
constant must first be assigned to a variable and then the address of
the variable passed.
As Fortran stores multi-dimension arrays in column major order whereas C stores in row major order, either
For example to call a routine called "NAGSUB" which in Fortran looks like this
SUBROUTINE NAGSUB(A,B,C)
CHARACTER A
CHARACTER*3 B
CHARACTER*5 C(2)
the C code looks like this.
extern void nagsub_(char* a, char *b, char c[],
int len_a, int len_b, int len_c);
main()
{
char a = 'a';
int len_a = 1;
char b[] = "abc";
int len_b = 3;
char c[2][6] = {"abcde", "fghij"};
int len_c = 5;
nagsub_(&a, b, (char *)c, len_a, len_b, len_c);
}
Note that the char variables' declared length in the C program must
allow space for the null termination in the C string.
The HP-UX 64-bit compiler uses long instead of int for the hidden length argument.
The Fortran type DOUBLE COMPLEX (or COMPLEX*16) is provided in the NAG header files by the typedef "Complex", which expands to "struct {double re,im;}"
Procedure arguments, i.e. function or subroutine names, are passed by address in the normal C manner.
DOUBLE COMPLEX FUNCTION F(X)
DOUBLE COMPLEX X
has the following prototype:
extern void f_(Complex *,Complex *);and a user callable function, e.g S01EAF, looks like this
extern void s01eaf_(Complex *return_value,const Complex *z,int *ifail);
Note that the NAGWare compiler has an option to use the de facto standard described above, but this is not used in the NAG Fortran Library implementations.
The prototype for the user supplied function F with HP-UX or NAGWare is the following.
Complex (*f)(Complex *)and a user callable function, e.g S01EAF, looks like this
extern Complex s01eaf_(const Complex *z,int *ifail);
One solution is to use the NAGWare Compiler implementation of the NAG Fortran Library, if available, please see above.
As it is impossible to access the return value of a DOUBLE COMPLEX FUNCTION from C, another solution is to write a Fortran "jacket" routine to convert the DOUBLE COMPLEX FUNCTION to a SUBROUTINE with an extra initial argument containing a pointer to the return value. The "jacket" routine then calls S01EAF.
For example to call S01EAF, write a jacket routine called S01EAFJ which would have the following prototype.
extern void s01eafj_(Complex *ret_val, CONST Complex *z,
int *ifail);
The jacket routine is then called from the C program rather than S01EAF.
SUBROUTINE S01EAFJ(RET_VAL, Z, IFAIL)
DOUBLE COMPLEX RET_VAL, Z, S01EAF
INTEGER IFAIL
RET_VAL = S01EAF(Z, IFAIL)
END
This routine can be compiled and linked with the C files and NAG
Fortran Library in the normal way.
Similar jacket routines can be written for user supplied functions.
The supplied C Header files do not contain prototypes for these jacket functions. Use the "Standard Unix" version of the C Header File on these systems and modify the prototypes appropriately.
e.g.
CHARACTER*10 FUNCTION F(I)is called thus:
extern void f_(char *,int,int *);
char c[10];
int clen = 10,i;
f_(&c,clen,&i)
The HP-UX 64-bit compiler uses long instead of int for the hidden length argument.
int array[] /* 2 dimension */
and for 3 dimensions:
double array[] /* 3 dimension */The prototype for a hypothetical NAG Fortran routine with a 2 dimensional DOUBLE PRECISION array argument would look like this:
extern void nagsub_(double[] /* 2 dimensions */);A simple program to call this routine might look like this:
main ()
{
double p[2][2];
nagsub_((double *)p);
}
Note that we need to cast the 2 dimensional C array actual argument to
(double *).
The example prototype below shows how to call a hypothetical NAG routine that takes a single subroutine argument. This user supplied subroutine takes a 2 dimension DOUBLE PRECISION array and an integer which specifies the leading dimension of the Fortran array.
extern void nagsub_(void (*f) (double[] /* 2 dimension */, int *));
The C code for the user supplied function is listed below. The 2 dimension array is passed as a pointer to double and the code must carry out array indexing using the dimension information passed from Fortran. In this case, the macro P uses the leading dimension of the Fortran array, which is the trailing dimension of the C array, to index into the array p. The array p is only referenced through this macro.
void fun(double p[], int *tdp)
{
#define P(I,J) p[(I) + (*tdp)*(J)]
P(0,0) = 0.0;
P(1,1) = 1.0;
}
The main function looks like this:
main ()
{
void fun(double p[], int *tdp);
nagsub_(fun);
}
Example 2 below shows a complete example program that illustrates
these concepts.
#ifdef __cplusplus
extern "C" {
#endif
(with a matching "}" at the end of the file)
| Platform | Complex Function Jacket | C Header Version |
| All NAGWare f95 Implementations | No | Complex Functions with underscore |
| HP9000/700 32-bit | No | Complex Functions without underscore |
| HP9000/700 64-bit | No | Specific HP64 Header File (with underscore) |
| IBM AIX | Yes | Standard Unix without underscore |
| IBM AIX using the -qextname option | Yes | Standard Unix with underscore |
| All Linux implementations using g77 or Intel Compilers | No | Standard Unix with underscore |
| Silicon Graphics | Yes | Standard Unix with underscore |
| Sun Solaris 32-bit | No | Standard Unix with underscore |
| Sun Solaris 64-bit | No | Complex Functions with underscore |
cc -c myprog.c f77 -o myprog myprog.o -lnagOn some systems this will not work and in some circumstances it is necessary to link using ld or cc. In which case it is necessary to specify the Fortran run time libraries in the load command. The libraries may be documented in the f77 man page or, failing that, the commands generated by the compiler driver may be viewed using the -v, -dryrun or -# options to display the ld command line.